home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Games
/
othello
/
Source
/
Othello.m
< prev
next >
Wrap
Text File
|
1992-09-27
|
8KB
|
332 lines
/* Generated by Interface Builder */
#import "Othello.h"
@implementation Othello
- saveGame:sender
{
NXStream *theStream;
if (!savePanel) savePanel = [SavePanel new];
if ([savePanel runModal]) {
theStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
NXWrite(theStream, theField, NUM_SPACES * sizeof(short));
NXWrite(theStream, &theTurn, sizeof(short));
NXFlush(theStream);
NXSaveToFile(theStream, [savePanel filename]);
NXClose(theStream);
}
return self;
}
- openGame:sender
{
NXStream *theStream;
static const char *const othType[2] = {"oth", NULL};
id openPanel = [[OpenPanel new] allowMultipleFiles:NO];
if ([openPanel runModalForTypes:othType]) {
theStream = NXMapFile([openPanel filename], NX_READONLY);
NXRead(theStream, theField, NUM_SPACES * sizeof(short));
NXRead(theStream, &theTurn, sizeof(short));
NXClose(theStream);
[self updateField:self];
}
return self;
}
int count_pieces(theField, thePlayer)
short *theField, thePlayer;
{
int i, count=0;
for(i=0; i<NUM_SPACES; i++) {
if(theField[i]==thePlayer) count++;
}
return count;
}
- newGame:sender
{
bzero(&theField, NUM_SPACES * sizeof(short));
/* this needs to be computed-- algorithm to find the middle for squares
* and place the appropriate pieces in those squares.
*/
theField[27]= WHITE;
theField[28]= BLACK;
theField[35]= BLACK;
theField[36]= WHITE;
[self updateField:self];
theTurn = WHITE;
theField[NUM_SPACES]=theTurn;
[status setStringValue:"White's turn."];
[white_number setIntValue:count_pieces(theField, WHITE)];
[black_number setIntValue:count_pieces(theField, BLACK)];
return self;
}
- updatePlace:(int) theCell forPlayer:(int) thePlayer
{
switch(thePlayer) {
case WHITE:
[[playField findCellWithTag:theCell] setIcon:"White_piece"];
break;
case BLACK:
[[playField findCellWithTag:theCell] setIcon:"Black_piece"];
break;
default:
[[playField findCellWithTag:theCell] setIcon:""];
}
return self;
}
- updateField:sender
{
int i;
for(i=0; i<NUM_SPACES; i++) {
switch(theField[i]) {
case WHITE:
[[playField findCellWithTag:i] setIcon:"White_piece"];
break;
case BLACK:
[[playField findCellWithTag:i] setIcon:"Black_piece"];
break;
default:
[[playField findCellWithTag:i] setIcon:""];
}
}
return self;
}
int opp(player)
int player;
{
if (player == WHITE) {
return BLACK;
}
return WHITE;
}
- (BOOL) checkDirection:(int) xDelta:(int) yDelta fromCell:(int)theCell
forPlayer:(int) thePlayer
{
int x = x(theCell)+xDelta;
int y = y(theCell)+yDelta;
int deltaCell = cell(x, y);
if(x < 0 || x > FIELD_WIDTH-1 || y < 0 || y > FIELD_HEIGHT-1) {
return NO;
}
while(theField[deltaCell] == opp(thePlayer)) {
x = x(deltaCell)+xDelta;
y = y(deltaCell)+yDelta;
if(x < 0 || x > FIELD_WIDTH-1 || y < 0 || y > FIELD_HEIGHT-1) {
return NO;
}
deltaCell=cell(x, y);
}
if (theField[deltaCell]==thePlayer) {
return YES;
}
return NO;
}
- (void) doDirection:(int) xDelta:(int) yDelta fromCell:(int)theCell
forPlayer:(int) thePlayer
{
int deltaCell=cell((x(theCell)+xDelta), (y(theCell)+yDelta));
while(theField[deltaCell] == opp(thePlayer)) {
theField[deltaCell] = thePlayer;
[self updatePlace:deltaCell forPlayer:thePlayer];
deltaCell=cell((x(deltaCell)+xDelta), (y(deltaCell)+yDelta));
}
}
- (BOOL) allDirectionsFromCell:(int)theCell flipPieces:(BOOL) move
forPlayer:(int) thePlayer
{
int xDelta, yDelta, x, y;
BOOL validMove=NO;
for (yDelta=-1; yDelta<2; yDelta++) {
y = y(theCell) + yDelta;
if (y < 0 || y > FIELD_HEIGHT-1) continue; /* off board */
for (xDelta=-1; xDelta<2; xDelta++) {
x = x(theCell) + xDelta;
if (x < 0 || x > FIELD_WIDTH-1) continue; /* off board */
if (theField[cell(x, y)] != opp(thePlayer)) continue; /* not flanked
by opponent */
/* there is an ajacent opponent this direction-- check to see if there
* is a flank and make the changes if there is. the eight directions
* that need to be changed are independent-- we can safely make the
* board changes w/o having to worry about an affect on the other
* directions.
*/
if ([self checkDirection:xDelta:yDelta fromCell:theCell
forPlayer:thePlayer]) {
if (move) [self doDirection:xDelta:yDelta fromCell:theCell
forPlayer:thePlayer];
validMove=YES;
}
}
}
return validMove;
}
- (BOOL) allDirectionsFromCell:(int)theCell flipPieces:(BOOL) move
{
return
[self allDirectionsFromCell:theCell flipPieces:move forPlayer:theTurn];
}
- (BOOL) canPlay:(int) thePlayer
{
int i;
/* if there is any move at all, immediately return YES. */
for(i=0; i<NUM_SPACES; i++) {
if(theField[i] == EMPTY)
if([self allDirectionsFromCell:i flipPieces:NO
forPlayer:thePlayer]) {
return YES;
}
}
/* otherwise, return NO. */
return NO;
}
- (char *) playerToString:(int) thePlayer
{
char *s;
s = malloc(6*sizeof(char));
if (thePlayer == WHITE) {
strcpy(s, "White");
} else strcpy(s, "Black");
return s;
}
- (char *) turnString
{
char *s;
s = malloc(15*sizeof(char));
strcpy(s, [self playerToString:theTurn]);
strcat(s, "'s turn.");
return s;
}
- moveMade:sender
{
char msg[25];
int theCell;
int white,black;
if ((theCell = [sender selectedTag]) < 0)
return self;/* invalid click trap */
if (theField[theCell]) return self; /* bad move -- already occupied */
/* try the move */
if([self allDirectionsFromCell:theCell flipPieces:NO]) {
[self backup];
[self allDirectionsFromCell:theCell flipPieces:YES];
theField[theCell] = theTurn; /* place the piece */
[self updatePlace: theCell forPlayer:theTurn];
/* check to see if the next player has a valid move available
* this could be combined w/the above but would dog out the board
* refresh and wouldn't be aesthetically pleasing
*/
if([self canPlay:opp(theTurn)]) {
theTurn=opp(theTurn);
theField[NUM_SPACES]=theTurn;
sprintf(msg, "%s's turn.", [self playerToString:theTurn]);
} else {
if(![self canPlay:theTurn]) {
white=count_pieces(theField, WHITE);
black=count_pieces(theField, BLACK);
if (black > white) {
sprintf(msg, "Black wins by %d.", black - white);
} else
if (white > black) {
sprintf(msg, "White wins by %d.", white - black);
} else sprintf(msg, "Tie game.");
} else
sprintf(msg, "%s has no move. %s's turn.",
[self playerToString:opp(theTurn)],
[self playerToString:theTurn]);
}
} else sprintf(msg, "Invalid move. %s's turn.",
[self playerToString:theTurn]);
[white_number setIntValue:count_pieces(theField, WHITE)];
[black_number setIntValue:count_pieces(theField, BLACK)];
[status setStringValue:msg];
return self;
}
- undo:sender
{
[self swap];
return self;
}
- swap
{
short temp[NUM_SPACES+1];
char msg[20];
bcopy(theBckField, temp, (NUM_SPACES+1) * sizeof(short));
bcopy(theField, theBckField, (NUM_SPACES+1) * sizeof(short));
bcopy(temp, theField, (NUM_SPACES+1) * sizeof(short));
[self updateField:self];
theTurn=theField[NUM_SPACES];
sprintf(msg, "%s", [self turnString]);
[status setStringValue:msg];
return self;
}
- backup
{
bcopy(theField, theBckField, NUM_SPACES * sizeof(short));
theBckField[NUM_SPACES] = theTurn;
return self;
}
- appDidInit:sender
{
[self newGame:self];
return self;
}
@end